package jfprincesstests.structures;

import java.util.*;

import jfprincesstests.fakes.*;
import jfuzzyprincepless.zarchive.algorithm.structure.IMultiConstruction;
import jfuzzyprincepless.zarchive.algorithm.structure.ifcnstr.INegotiationCondition;
import jfuzzyprincepless.zarchive.algorithm.structure.ifcnstr.NegotiationIfConstruction;
import jfuzzyprincepless.zarchive.algorithm.structure.forcnstr.NegotiationForAbsEach;
import jfuzzyprincepless.zarchive.algorithm.structure.forcnstr.fuzzyfor.NegotiationFuzzyFor;
import jfuzzyprincepless.zarchive.algorithm.structure.ChainCommand;
import jfuzzyprincepless.zarchive.algorithm.structure.ICommandConstruction;
import jfuzzyprincepless.negotiation.*;
import jfuzzyprincepless.zarchive.variables.FuzzySet;
import jfuzzyprincepless.zarchive.variables.IFuzzySet;
import jfuzzyprincepless.zarchive.negotiation.IAgentsExporter;
import jfuzzyprincepless.zarchive.negotiation.services.IExecuteIfService;
import jfuzzyprincepless.agents.INegotiatingAgent;
import laboratoryQ.junit.ignore.patch.BaseTestCase;
import laboratoryQ.computation.BaseUtils;

public class TestCommands extends BaseTestCase {
	public void testChainCommand() {
		StringBuilder sb = new StringBuilder();

		ICommandConstruction cmd = new ChainCommand(
			new FakeCmd(sb, "0"),
			new FakeCmd(sb, "1")
		);
		assertEquals("", sb.toString());

		final IExecutionContext fakeContext =
			new IExecutionContext() { };
		cmd.execute(fakeContext);
		assertEquals("0;1;", sb.toString());

		cmd = new ChainCommand(
			new FakeCmd(sb, "3"),
			new FakeCmd(sb, "4"),
			new FakeCmd(sb, "5"),
			new ICommandConstruction() {
				@Override
				public void execute(IExecutionContext context) {
					assertSame(fakeContext, context);
				}
			}
		);

		sb.setLength(0);
		cmd.execute(fakeContext);
		assertEquals("3;4;5;", sb.toString());
	}

	public void testChainCommand_commandList() {
		StringBuilder sb = new StringBuilder();

		ChainCommand cmd = new ChainCommand(
			new FakeCmd(sb, "0"),
			new FakeCmd(sb, "1")
		);
		assertEquals("", sb.toString());

		cmd.execute(IExecutionContext.EMPTY);
		assertEquals("0;1;", sb.toString());

		sb.setLength(0);
		cmd.getCommandsList().add(new FakeCmd(sb, "3"));
		cmd.execute(IExecutionContext.EMPTY);
		assertEquals("0;1;3;", sb.toString());
	}

	public void testChainCommand_staticExecute() {
		StringBuilder sb = new StringBuilder();

		List<FakeCmd> cmdList = Arrays.asList(
			new FakeCmd(sb, "0"),
			new FakeCmd(sb, "1")
		);
		ChainCommand.executeCmdList(cmdList, null);
		assertEquals("0;1;", sb.toString());
	}

	public void testChainCommand_multicmd_agentexp() {
		StringBuilder sb = new StringBuilder();

		FakeActivator agentcmdA = new FakeActivator(sb, "agA");
		FakeActivator agentcmdB = new FakeActivator(sb, "agB");
		FakeCmd fakecmd = new FakeCmd(sb, "cmd");

		ChainCommand cmd = new ChainCommand(
			agentcmdA,
			agentcmdB,
			fakecmd
		);

		IAgentsExporter agentsExporter = cmd;
		IMultiConstruction multiConstruction = cmd;

		assertEquals(
			Arrays.asList(agentcmdA, agentcmdB, fakecmd),
			multiConstruction.getCommandsList()
		);

		assertEquals(
			Collections.<INegotiatingAgent>emptyList(),
			agentsExporter.getAgents()
		);

		cmd.extractAgentsFromConstructions();

		assertEquals(
			Arrays.<INegotiatingAgent>asList(agentcmdA, agentcmdB),
			agentsExporter.getAgents()
		);

		NegotiationUtils.defaultNegotiationIteration(
			agentsExporter.getAgents(),
			new DefaultNegotiationContext()
		);
		assertEquals("agAagB", sb.toString());
	}

	/**
	 * tests correct work of inner construction
	 * inner construction must add itself to context as service
	 */
	public void testContextExtensionInExecution() {
		final StringBuilder sb = new StringBuilder();

		// IF inside FOR
		FakeActivationCmd fakeCmd =
			new FakeActivationCmd(
				new FakeForCmd<Integer>(sb, ";cmd")
			);
		NegotiationIfConstruction ifCommand =
			new NegotiationIfConstruction(
				INegotiationCondition.EMPTY_CONDITION,
				Arrays.<ICommandConstruction>asList(
					fakeCmd
				),
				Collections.<ICommandConstruction>emptyList(),
				Arrays.<INegotiatingAgent>asList(
					new FakeActivator(fakeCmd, sb, ";neg")
				)
			);

		NegotiationForAbsEach<Integer> forLoop =
			new NegotiationForAbsEach<Integer>(
				Arrays.asList(1, 2, 3),
				ifCommand
			);
		forLoop.extractAgentsFromConstructions();

		forLoop.execute(new DefaultNegotiationContext());

		assertEquals(";neg;cmd1;neg;cmd2;neg;cmd3", sb.toString());

		// FOR inside IF
		sb.setLength(0);

		FakeActivationCmd fakeIfCmd = new FakeActivationCmd(
			new ICommandConstruction() {
				@Override
				public void execute(IExecutionContext econtext) {
					INegotiationContext context =
						(INegotiationContext)econtext;
					IExecuteIfService ifServ =
						context.getService(IExecuteIfService.class);
					assertSame(
						INegotiationCondition.EMPTY_CONDITION,
						ifServ.getIfConstruction().getCondition()
					);
					sb.append(";if-cmd");
				}
			}
		);

		forLoop = new NegotiationForAbsEach<Integer>(
			Arrays.asList(1, 2, 3),
			new ICommandConstruction[] {
				fakeIfCmd,
				fakeCmd
			},
			Arrays.<INegotiatingAgent>asList(
				new FakeActivator(fakeIfCmd, sb, ";if-neg"),
				new FakeActivator(fakeCmd, sb, ";neg"),
				new FakeForAgetn<Integer>(sb, ";for-neg")
			)
		);

		ifCommand = new NegotiationIfConstruction(
			INegotiationCondition.EMPTY_CONDITION,
			Arrays.<ICommandConstruction>asList(
				forLoop
			),
			Collections.<ICommandConstruction>emptyList()
		);
		ifCommand.extractAgentsFromConstructions();

		ifCommand.execute(new DefaultNegotiationContext());

		assertEquals(
			";if-neg;neg;for-neg1;if-cmd;cmd1" +
			";if-neg;neg;for-neg2;if-cmd;cmd2" +
			";if-neg;neg;for-neg3;if-cmd;cmd3",
			sb.toString()
		);

		// FUZZY-FOR inside IF
		sb.setLength(0);

		IFuzzySet<Integer> fuzzySet = new FuzzySet<Integer>();
		fuzzySet.add(1, 0.1);
		fuzzySet.add(2, 0.2);
		fuzzySet.add(3, 0.3);
		NegotiationFuzzyFor<Integer> fuzzyForLoop =
			new NegotiationFuzzyFor<Integer>(
				fuzzySet,
				new ICommandConstruction[] {
					fakeIfCmd,
					fakeCmd
				},
				Arrays.<INegotiatingAgent>asList(
					new FakeActivator(fakeIfCmd, sb, ";if-neg"),
					new FakeActivator(fakeCmd, sb, ";neg"),
					new FakeForAgetn<Integer>(sb, ";for-neg")
				)
			);

		ifCommand = new NegotiationIfConstruction(
			INegotiationCondition.EMPTY_CONDITION,
			Arrays.<ICommandConstruction>asList(
				fuzzyForLoop
			),
			Collections.<ICommandConstruction>emptyList()
		);
		ifCommand.extractAgentsFromConstructions();

		ifCommand.execute(new DefaultNegotiationContext());

		assertEquals(
			";if-neg;neg;for-neg1mem0.1;if-cmd;cmd1mem0.1" +
			";if-neg;neg;for-neg2mem0.2;if-cmd;cmd2mem0.2" +
			";if-neg;neg;for-neg3mem0.3;if-cmd;cmd3mem0.3",
			sb.toString()
		);
	}

	public void testAct_IF_inside_FuzzyFOR() {
		StringBuilder sb = new StringBuilder();
		ICommandConstruction thenCmd = new FakeForCmd<Integer>(sb, ";then");
		ICommandConstruction elseCmd = new FakeForCmd<Integer>(sb, ";else");
		FakeCondition condition = new FakeCondition(Double.NaN);
		NegotiationIfConstruction ifConstruction = new NegotiationIfConstruction(
			condition,
			Arrays.<ICommandConstruction>asList(new FakeActivationCmd(thenCmd)),
			Arrays.<ICommandConstruction>asList(new FakeActivationCmd(elseCmd))
		);
		ifConstruction.extractAgentsFromConstructions();
		BaseUtils.insertToList(
			ifConstruction.getAgents(),
			0,
			new FakeSetTruthDegreeFromFor<Integer>(condition)
		);

		IFuzzySet<Integer> fSet = new FuzzySet<Integer>();
		fSet.add(1, 0.1);
		fSet.add(2, 0.5);
		fSet.add(3, 0.9);
		NegotiationFuzzyFor<Integer> forConstruction =
			new NegotiationFuzzyFor<Integer>(
				fSet,
				ifConstruction
			);
		forConstruction.extractAgentsFromConstructions();

		forConstruction.execute(new DefaultNegotiationContext());

		assertEquals(
			";else1mem0.1;else2mem0.5;then3mem0.9",
			sb.toString()
		);
	}
}
